package de.fhhof.robot.control;

import de.fhhof.robot.control.cmd.concreate.MessageState;
import de.fhhof.robot.control.common.MessageUtility;
import de.fhhof.robot.control.common.Utility;
import de.fhhof.robot.control.impl.ControlToRobot;
import de.fhhof.robot.control.impl.ControlToStorage;
import de.fhhof.robot.control.net.IConnection;

public class ConcreateWrokFlowCommand extends AWorkFlowCommand {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public ConcreateWrokFlowCommand(){
	}
	@Override
	public IMessage execute() throws InvalidOperation {
		
		if(!this.state.toString().equals(ExecutionState.DONE.toString())){
			this.state = ExecutionState.RUNNING;
		}
		
		IConnection slConn = ControlToStorage.getStorageConnection();
		IConnection srConn = ControlToRobot.getRobotConnection();
		
		int required = this.requiredSmarties - this.completedSmarties;
		
		while(  this.completedSmarties < this.requiredSmarties){

			
			/** 1. Get the palate from storage */
			//System.out.println("Step: 1. Generating pattern for color: "+ this.color.getCode());
			
			String storagePattern = "";
			//int receivedSmarties = 0;
			
			if(!this.assemblyState.getCmdState().isMsgToStorage()){
				
				String strPayLoad = getAPalleteFromStorage(required,slConn).getPayload();
				
				currentTrayNo = strPayLoad.substring(0, 3);
				storagePattern =  strPayLoad.substring(3);
				this.receivedSmarties = MessageUtility.getRequiredColor(color, storagePattern);
				
				System.out.println("Step 1: Received smarties from storage: "+ this.receivedSmarties);
				
				if(this.receivedSmarties < 1){
					System.out.println("Invlid color of smarties from storage: "+ storagePattern + " for color: " + this.color.getCode());
					throw new InvalidOperation();
				}
				this.assemblyState.getCmdState().setMsgToStorage(true);
				this.saveAssembly();
			}

			System.out.println();
			boolean hasErrorInAssemble = false;
			boolean hasRobotErrorInTakingStorageSmarties = false;
			
			try{
				/** 2. Put the storage palate to robot control area */
				if(!this.assemblyState.getCmdState().isHasStoragePallateInsideRobot()){
					
					System.out.println("Step: 2. Putting storage smarties to robot for color: "+ this.color.getCode());
					IMessage messageRobo = new Message("K000", storagePattern);
					IMessage ack2R = this.sendMessage(messageRobo, srConn, this.assemblyState.getCmdState().getMsgStoragePallateInsideRobotState());
					
					System.out.println("Response from robot: "+ ack2R.getCommand() + " payload: "+ ack2R.getPayload());
					
					this.assemblyState.getCmdState().setHasStoragePallateInsideRobot(true);
					this.saveAssembly();

				}				
			}
			catch(Exception ex){
				hasRobotErrorInTakingStorageSmarties = true;
			}

			if(!hasRobotErrorInTakingStorageSmarties){
				try{
					/** 3. Assemble the pattern using the smarties that are available in storage palate */
					if(!this.assemblyState.getCmdState().isAssembling()){
						
						int toDraw = 0;
						if(this.receivedSmarties < required){
							toDraw = this.receivedSmarties; 
						}else{
							toDraw = required;
						}
						
						String samplePattern = createPattern(toDraw,this.completedSmarties,this.message.getPayload());
						System.out.println("Step 3. Assemble pattern for color:"+ this.color.getCode() +" ::"+ samplePattern);
						
						IMessage msgAssemble = new Message("K002", samplePattern);
						IMessage ack2RAsm =  this.sendMessage(msgAssemble, srConn, this.assemblyState.getCmdState().getMsgAssemblingState());

						System.out.println("Response from robot: "+ ack2RAsm.getCommand() + " payload: "+ ack2RAsm.getPayload());
						System.out.println();		
						
						this.assemblyState.getCmdState().setAssembling(true);
						this.saveAssembly();
					}				
				}
				catch(InvalidOperation in){
					hasErrorInAssemble = true;
				}

				/** 4. Remove storage palate from robot area to transfer point */
				if(!this.assemblyState.getCmdState().isHasRemovedStoragePalate()){
					System.out.println("Step 4. Removing storage palate from robot area for color: "+ this.color.getCode() +" ");
					
					IMessage removeStoragePalateMsg = new Message("K003", "");
					
					IMessage ack2Rrm = this.sendMessage(removeStoragePalateMsg, srConn, this.assemblyState.getCmdState().getMsgRemoveStoragePalateState());
					
					System.out.println("Message to robot to remove the storage palate: "+ removeStoragePalateMsg.getCommand() + " payload: "+ removeStoragePalateMsg.getPayload());
					System.out.println("Response from robot: "+ ack2Rrm.getCommand() + " payload: "+ ack2Rrm.getPayload());
					
					returnPalatePattern = ack2Rrm.getPayload();
					System.out.println("New storage palate pattern after rendering a pattern by robot"+ returnPalatePattern);
					
					int returnFromRobot = MessageUtility.getRequiredColor(color, returnPalatePattern);
					
					System.out.println("Received smarties from Robot in new pattern : "+ returnFromRobot);
					System.out.println();	
					
					this.assemblyState.getCmdState().setHasRemovedStoragePalate(true);
					this.saveAssembly();				
				}				
			}


			
			/** 5. Put the storage palate to storage  */
			if(!this.assemblyState.getCmdState().isHasReturnStoragePalateToStorage()){
				System.out.println("Step 5. Putting storage palate to storage  for color: "+ this.color.getCode() +" ");
				
				String newPayLoadForStorage = currentTrayNo + "" + returnPalatePattern;
				if(hasRobotErrorInTakingStorageSmarties){
					newPayLoadForStorage = currentTrayNo + "" + storagePattern;
				}

				IMessage msgToStorage = new Message("K004", newPayLoadForStorage);
				IMessage ack2sl = this.sendMessage(msgToStorage, slConn, this.assemblyState.getCmdState().getMsgReturnStoragePalateToStorageState());
				
				System.out.println("Message to storage to restore the storage palate: "+ msgToStorage.getCommand() + " payload: "+ msgToStorage.getPayload());
				System.out.println("Response from storage : "+ ack2sl.getCommand() + " payload: "+ ack2sl.getPayload());
				System.out.println();		
				
				this.assemblyState.getCmdState().setHasReturnStoragePalateToStorage(true);
				this.saveAssembly();					
			}
			
			if(hasErrorInAssemble || hasRobotErrorInTakingStorageSmarties){
				throw new InvalidOperation();
			}
			if(this.receivedSmarties < required){
				this.completedSmarties += this.receivedSmarties;
			}
			else{
				this.completedSmarties += required;
			}
			
			required = this.requiredSmarties - this.completedSmarties ;
			
			this.receivedSmarties = 0;
			this.finalizeCmd();
			this.saveAssembly();
		}
		String val = Utility.pad(this.completedSmarties+ "",2);
		IMessage cmdMessage = new Message("A002", this.color.getCode()+val);
		this.finalizeCmd();
		
		return cmdMessage;
	}
	private IMessage getAPalleteFromStorage(int required,IConnection slConn){
		
		String payLoad = findPayload(required);
		IMessage msg1 = new Message("K005", payLoad);
		return this.sendMessage(msg1, slConn, this.assemblyState.getCmdState().getMsgToStrageState());	
	}
	private IMessage sendMessage(IMessage msg,IConnection conn,MessageState state){
		return Utility.sendMessage(msg, conn, state, this.assemblyState);
	}
	private void finalizeCmd(){
		this.assemblyState.setCmdState(new CmdState());
	}
	private String createPattern(int required,int completed,String pattern){
		
		StringBuffer buf = new StringBuffer();
		
		for(int index=0; index<pattern.length();index++){
			char ch = pattern.charAt(index);
			if(ch == this.color.getCode() && completed > 0){
				buf.append('-');
				completed--;
			
			}
			else if(ch == this.color.getCode() && required >0){
				buf.append(ch);
				required--;
			}
			else{
				buf.append('-');
			}
			
		}
		return buf.toString();
	}
	private String findPayload(int smarties){
		String payload = this.color.getCode() +"";
		String count = Utility.pad(smarties+"", 3);
		return payload+count;
	}
	
	public static void main(String args[]){
		
		
		ConcreateWrokFlowCommand s = new ConcreateWrokFlowCommand();
		
		s.setColor(Color.RED);
		String ss = s.createPattern(3, 0, "rrrrrrr----bbbbb-rrrrrr");
		
		System.out.println(ss);
		String ss1 = s.createPattern(7, 3, "rrrrrrr----bbbbb-rrrrrr");
		
		System.out.println(ss1);
		String ss11 = s.createPattern(3, 10, "rrrrrrr----bbbbb-rrrrrr");
		
		System.out.println(ss11);
		
	}

}
